package com.zhanglijie.improve.aqs.exclusive;

import java.io.Serializable;
import java.util.List;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;

import com.zhanglijie.theory.readwrite.MyReadWriteLock;

/**
 * @author zhanglijie
 * @version 1.0
 * @since 1.1.0 2022/9/11 0011 17:41
 */
public class MyReentrantLock implements Lock, Serializable {
    private final MySync sync;

    /**
     * 无参默认构造方法是 非公平锁
     */
    public MyReentrantLock( ) {
        this.sync = new MyUnFairSync();
    }
    public MyReentrantLock(boolean isFair){
        this.sync = isFair?new MyFairSync():new MyUnFairSync();
    }

    /**
     * 公平/非公平锁 ->MySync->MyAbstractQueuedSynchronized
     */
    abstract static class MySync extends MyAbstractQueuedSynchronizer{
        /**
         * 加锁 有公平非公平区分 所以抽象出来
         */
        abstract void lock();
        final boolean nonfairTryAcquire(int arg) {
            Thread currentThread = Thread.currentThread();
            int state = getState();
            if(state == 0){
                //不检查是否有人排队直接cas(非公平）
                if(compareAndSetState(0,arg)){
                    //cas 成功了 表明已经拿到锁了
                    setOwnerThread(currentThread);
                    return true;
                }

            }else if(currentThread == getOwnerThread()){//判断当前线程是否已经拿到锁了 （重入） state++
                int newState = state+arg;
                if(newState < 0){
                    throw new Error("数据错误！");
                }
                setState(newState);
                return true;
            }
            return false;
        }

        /**
         * 释放锁  公平和非公平释放都一样 所以放到父类中具体实现即可  实现在MyAbstractQueuedSynchronizer 中 具体干活放在下面方法中
         */
        @Override
        public boolean tryRelease(int arg)   {
            int i = getState()-arg;
            if(Thread.currentThread() != getOwnerThread()){
                throw new IllegalMonitorStateException();
            }
            boolean free = false;
            if(i == 0){
                free = true;
                setOwnerThread(null);//只有一个线程执行 所以安全
            }
            setState(i);//只有一个线程执行 所以安全
            return free;
        }

        public  Condition newCondition(){
            return new ConditionObject();
        }


        @Override
        protected boolean isHeldExclusively() {
            return getOwnerThread() == Thread.currentThread();
        }
    }

    /**
     * 公平锁
     */
    static class MyFairSync extends MySync{

        @Override
        void lock() {
          acquire(1);
        }

        /**
         * 尝试快速获取锁
         * @return
         */
        @Override
        public boolean tryAcquire(int arg){
            Thread currentThread = Thread.currentThread();
            int state = getState();
            if(state == 0){
                //检查队列，如果没有人排队才进行cas操作  如果有人在排队 那么只能排队去
                if(!hasQueuePred() && compareAndSetState(0,arg)){
                    //cas 成功了 表明已经拿到锁了,而且只能一个线程能拿到,所以下面的set的对象只要volatile修饰就可以不需要加锁set
                     setOwnerThread(currentThread);
                    return true;
                }

            }else if(currentThread == getOwnerThread()){//判断当前线程是否已经拿到锁了 （重入） state++
                int newState = state+arg;
                if(newState < 0){
                    throw new Error("数据错误！");
                }
                setState(newState);
                return true;
            }
            return false;
        }

    }

    /**
     * 非公平锁
     */
    static class MyUnFairSync extends MySync{

        @Override
        void lock() {
            //上来就抢 对于非公平锁
            if(compareAndSetState(0,1)){
                setOwnerThread(Thread.currentThread());
            }else{
                acquire(1);
            }
        }
        @Override
        public boolean tryAcquire(int arg){
            return nonfairTryAcquire(arg);
        }
    }

    @Override
    public void lock() {
        //分公平锁和非公平锁
       sync.lock();
    }

    @Override
    public void unlock() {
        sync.release();
    }

    @Override
    public Condition newCondition() {
        return sync.newCondition();
    }


    public List<Thread> getQueuedThreads(){
        return sync.getQueuedThreads();
    }
    @Override
    public boolean tryLock() {
        return sync.nonfairTryAcquire(1);
    }

    @Override
    public boolean tryLock(long time, TimeUnit unit) throws InterruptedException {
        return false;
    }
    @Override
    public void lockInterruptibly() throws InterruptedException {
        sync.acquireInterruptibly(1);
    }
}
